#include "charge_os.h"
#include "time.h"

#if SUPPORT_SYSTEM_OS == LINUX
    //#include "./linux/charge_os_linux.c"

#elif SUPPORT_SYSTEM_OS == FREERTOS

    #include "./freertos/charge_os_freertos.c"

#elif SUPPORT_SYSTEM_OS == NO_OS

    #include "./no_os/charge_os_no.c"

#else
    #error NOT_SUPPORT

#endif

#define LOG_LINE_BUF_SIZE                   256

/* every line log's buffer */
static char log_buf[LOG_LINE_BUF_SIZE] = { 0 };
static int32_t dm[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static os_timestamp_t mon_yday[2][12] =
{
    {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
    {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335},
};

/* level output info */
static const char *level_output_info[] =
{
    [LOG_LVL_ERROR]   = "E/",
    [LOG_LVL_WARN]    = "W/",
    [LOG_LVL_DEBUG]   = "D/",
};

/***********************************************************************************************
                                时间处理相关
***********************************************************************************************/

static void day_date(uint32_t day, struct os_time *ot)
{
    int32_t y = 0, m = 0, d = day + 1; /* d days has passed, now are d + 1 */
    int32_t i = 0;

    y = d / 365;
    d -= 365 * y;
    d -= y / 4 - y / 100 + y / 400; // num of leap years

    while (d <= 0)
    {
        if (!(y % 400) || (y % 4 == 0 && y % 100))
        {
            d += 1;
        }
        d += 365;
        y -= 1;
    }
    y += 1970;

    if (!(y % 400) || (y % 4 == 0 && y % 100))
    {
        dm[1] = 29; /* modify days of February */
    }

    for (i = 0; i < 12; i++)
    {
        if (d - dm[i] > 0)
        {
            d -= dm[i];
        }
        else
        {
            m = i;
            break;
        }
    }
    m += 1;

    ot->year = y;
    ot->mon = m;
    ot->day = d;
}

//void os_ts_to_time(uint32_t tick, struct os_time *ot)
//{
//    struct os_time date;
//    // tick += 8 * 60 * 60; // peking time 本地时间不需要调整
//    ot->sec = tick % 60;
//    tick /= 60;
//    ot->min = tick % 60;
//    tick /= 60;
//    ot->hour = tick % 24;
//    tick /= 24;
    /* tick are now days from 1970-01-01 */

//    ot->week = ((tick + 4) - 1) % 7 + 1; /* 1970-01-01 is Thursday */
//    day_date(tick, &date);
//    ot->year = date.year;
//    ot->mon = date.mon;
//    ot->day = date.day;
//}

//20210621  add by cz
void os_ts_to_time(uint32_t tick, struct os_time *ot)
{
#if 0
    unsigned int Pass4year;
    int hours_per_year;
    int day = 0;

    //tick += 8 * 60 * 60; // peking tick

    day = tick / (24 * 3600);
    ot->week = ((day + 4) - 1) % 7 + 1; /* 1970-01-01 is Thursday */

    //取秒时间
    ot->sec = (int)(tick % 60);
    tick /= 60;
    //取分钟时间
    ot->min = (int)(tick % 60);
    tick /= 60;

    //取过去多少个四年，每四年有 1461*24 小时
    Pass4year = ((unsigned int)tick / (1461L * 24L));
    //计算年份
    ot->year = (Pass4year << 2) + 1970;
    //四年中剩下的小时数
    tick %= 1461L * 24L;
    //校正闰年影响的年份，计算一年中剩下的小时数
    for (;;)
    {
        //一年的小时数
        hours_per_year = 365 * 24;
        //判断闰年
        if ((ot->year & 3) == 0)
        {
            //是闰年，一年则多24小时，即一天
            hours_per_year += 24;
        }
        if (tick < hours_per_year)
        {
            break;
        }
        ot->year++;
        tick -= hours_per_year;
    }
    //小时数
    ot->hour = (int)(tick % 24);
    //一年中剩下的天数
    tick /= 24;
    //假定为闰年
    tick++;
    //校正闰年的误差，计算月份，日期
    if ((ot->year & 3) == 0)
    {
        if (tick > 60)
        {
            tick--;
        }
        else
        {
            if (tick == 60)
            {
                ot->mon = 2; //这个不是数组下标
                ot->day = 29;
                return;
            }
        }
    }
    //计算月日
    for (ot->mon = 0; dm[ot->mon] < tick; ot->mon++)
    {
        tick -= dm[ot->mon];
    }

    ot->day = (int)(tick);

    ot->mon += 1;
#else
    struct tm *ptm;
	time_t time = tick;
	if ((ptm = localtime(&time)) != NULL)
	{
		// printf("\r\n gtm: %d-%d-%d %d:%d:%d", ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday,
		//		ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
		ot->sec = ptm->tm_sec;
		ot->min = ptm->tm_min;
		ot->hour = ptm->tm_hour;
		ot->week = ptm->tm_wday + 1;
		ot->day  = ptm->tm_mday;
		ot->mon =  ptm->tm_mon + 1;
		ot->year = ptm->tm_year + 1900;
	}
#endif
}
//20210621 add by cz  end

void os_server_ts_to_time(uint32_t tick, struct os_time *ot)
{
#if 0
    struct os_time date;
    tick += 8 * 60 * 60; // peking time 服务器时间下发调整
    ot->sec = tick % 60;
    tick /= 60;
    ot->min = tick % 60;
    tick /= 60;
    ot->hour = tick % 24;
    tick /= 24;
    /* tick are now days from 1970-01-01 */

    ot->week = ((tick + 4) - 1) % 7 + 1; /* 1970-01-01 is Thursday */
    day_date(tick, &date);
    ot->year = date.year;
    ot->mon = date.mon;
    ot->day = date.day;
#else
    struct tm *ptm;
	// peking time 服务器时间下发调整
	time_t time = tick + 8 * 60 * 60;
	if ((ptm = localtime(&time)) != NULL)
	{
		// printf("\r\n gtm: %d-%d-%d %d:%d:%d", ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday,
		//		ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
		ot->sec = ptm->tm_sec;
		ot->min = ptm->tm_min;
		ot->hour = ptm->tm_hour;
		ot->week = ptm->tm_wday + 1;
		ot->day  = ptm->tm_mday;
		ot->mon =  ptm->tm_mon + 1;
		ot->year = ptm->tm_year + 1900;
	}
#endif
}

static int isleap(int year)
{
    return (year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0);
}

os_timestamp_t os_time_to_ts(struct os_time ot)
{
    time_t result;
    int i = 0;
    struct tm os_tm;

#if 0
    // 以平年时间计算的秒数
    result = (ot.year - 1970) * 365 * 24 * 3600 + \
             (mon_yday[isleap(ot.year)][ot.mon - 1] + ot.day - 1) * 24 * 3600 + \
             ot.hour * 3600 + ot.min * 60 + ot.sec;
    // 加上闰年的秒数
    for (i = 1970; i < ot.year; i++)
    {
        if (isleap(i))
        {
            result += 24 * 3600;
        }
    }
    result -= 8 * 60 * 60; // peking time

#else
    os_tm.tm_year = ot.year - 1900;
	os_tm.tm_mon = ot.mon - 1;
	os_tm.tm_mday = ot.day;
	os_tm.tm_hour = ot.hour;
	os_tm.tm_min  = ot.min;
	os_tm.tm_sec  = ot.sec;
	os_tm.tm_wday = ot.week - 1;
	result = mktime(&os_tm);
	result -= 8*3600;
#endif
	return (result);
}

static char *get_time_str(void)
{
    static char __time_str[12];
    static struct os_time ot;

    os_ts_to_time(os_get_time(), &ot);
    snprintf(__time_str, 12, "%02d#%02d:%02d:%02d", ot.day, ot.hour, ot.min, ot.sec);
    __time_str[11] = '\0';

    return __time_str;
}

/**
 * another copy string function
 *
 * @param cur_len current copied log length, max size is ELOG_LINE_BUF_SIZE
 * @param dst destination
 * @param src source
 *
 * @return copied length
 */
static uint32_t log_strcpy(uint32_t cur_len, char *dst, const char *src)
{
    const char *src_old = src;

    while (*src != 0)
    {
        /* make sure destination has enough space */
        if (cur_len++ < LOG_LINE_BUF_SIZE)
        {
            *dst++ = *src++;
        }
        else
        {
            break;
        }
    }

    return src - src_old;
}

void log_output_lock(void)
{
#if SUPPORT_SYSTEM_OS == FREERTOS
    taskENTER_CRITICAL();
#else
#endif
}

void log_output_unlock(void)
{
#if SUPPORT_SYSTEM_OS == FREERTOS
    taskEXIT_CRITICAL();
#else
#endif
}

void log_output(uint8_t level, char *format, ...)
{
    va_list args;
    uint32_t len = 0;
    uint32_t log_head_len = 0;

    /* lock output */
    log_output_lock();

    if (level != 0xFF)
    {
        /* package level info */
        log_head_len += log_strcpy(log_head_len, log_buf + log_head_len, level_output_info[level]);
        log_head_len += log_strcpy(log_head_len, log_buf + log_head_len, " [");
        log_head_len += log_strcpy(log_head_len, log_buf + log_head_len, get_time_str());
        log_head_len += log_strcpy(log_head_len, log_buf + log_head_len, "] ");
    }

    va_start(args, format);
    len = vsnprintf((log_buf + log_head_len), (LOG_LINE_BUF_SIZE - log_head_len), format, args);
    va_end(args);

    log_buf[log_head_len + len] = '\0';

    os_print(log_buf);

    /* unlock output */
    log_output_unlock();
}
